package org.lionsoul.websnail.downloader.webdriver;

import org.lionsoul.websnail.downloader.Proxy;
import org.lionsoul.websnail.downloader.WebDriverProcessor;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedCondition;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Webdriver 构造器默认实现
 *
 * @author yangjian
 **/
public class DefaultWebDriverBuilder implements WebDriverBuilder
{

    // 最多创建多少个 WebDriver 实例
    private final int driverPoolSize;
    private ChromeOptions options;
    // WebDriver 资源池，WebDriver 复用，不用频繁的打开和关闭浏览器，节省资源
    private final List<SnailWebDriver> driverPool;
    private final ReentrantLock lock;
    // 等待页面加载完成的条件，如果为空的话，则会默认等待 3 秒钟让页面加载完成
    private ExpectedCondition<WebElement> condition;
    // 要获取的页面元素选择器，如果为空的话，则获取整个 <html> 标签的内容
    private By selector;
    // 设置代理
    private final Proxy proxy;


    public DefaultWebDriverBuilder(int driverPoolSize, ChromeOptions options, Proxy proxy)
    {
        this.driverPoolSize = driverPoolSize;
        this.options = options;
        this.proxy = proxy;
        this.driverPool = new CopyOnWriteArrayList<>();
        this.lock = new ReentrantLock();
    }

    public DefaultWebDriverBuilder(int driverPoolSize, Proxy proxy)
    {
        this(driverPoolSize, null, proxy);
    }

    public DefaultWebDriverBuilder(int driverPoolSize)
    {
        this(driverPoolSize, null, null);
    }

    public DefaultWebDriverBuilder(int driverPoolSize, ChromeOptions options)
    {
        this(driverPoolSize, options, null);
    }

    // get a LockedWebDriver object
    public SnailWebDriver build(WebDriverProcessor processor)
    {
        lock.lock();
        // WebDriver pool is full, take the idle one
        if (this.driverPool.size() >= driverPoolSize) {
            for (SnailWebDriver webDriver : driverPool) {
                if (webDriver.getState() == SnailWebDriver.IDLE) {
                    // 将 Driver 状态设置为运行中
                    webDriver.setState(SnailWebDriver.RUNNING);
                    lock.unlock();
                    return webDriver;
                }
            }
            lock.unlock();
            return null;
        }

        if (null == options) {
            options = new ChromeOptions();
        }
        // 设置代理
        if (null != proxy && null == options.getCapability("proxy")) {
            String proxyArg = String.format("--proxy-server=%s://%s:%d", proxy.getProtocol(), proxy.getHost(), proxy.getPort());
            options.addArguments(proxyArg);
        }
        // 创建一个新的 WebDriver 对象
        SnailWebDriver driver = new SnailWebDriver(new ChromeDriver(options), condition, selector);
        driver.setState(SnailWebDriver.RUNNING);
        // 添加到 WebDriver 缓存
        driverPool.add(driver);

        // WebDriver 的一些初始化操作
        if (processor != null) {
            processor.initialize(driver);
        }
        lock.unlock();
        return driver;
    }

    public ChromeOptions getOptions()
    {
        return options;
    }

    public ExpectedCondition<WebElement> getCondition()
    {
        return condition;
    }

    public void setCondition(ExpectedCondition<WebElement> condition)
    {
        this.condition = condition;
    }

    public By getSelector()
    {
        return selector;
    }

    public void setSelector(By selector)
    {
        this.selector = selector;
    }

    @Override
    public void close()
    {
        for (SnailWebDriver driver : driverPool) {
            driver.getWebDriver().quit();
        }
    }
}
